#pragma once
#include <Poco/DateTimeFormatter.h>
#include <Poco/Net/NetException.h>
#include <Poco/Net/ServerSocket.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Net/StreamSocket.h>
#include <Poco/Net/TCPServer.h>
#include <Poco/Net/TCPServerParams.h>
#include <Poco/Timestamp.h>
#include <Poco/Util/Application.h>
#include <Poco/Util/ServerApplication.h>

#include "Common/Logger.h"
#include "FServer/MySQL/MySQLTCPHandler.h"

namespace keeper_server {


class FServer : public Poco::Util::ServerApplication {
 public:
  FServer() {}
  ~FServer() {}
  int run() override { return Poco::Util::Application::run(); }

 protected:
  void defineOptions(Poco::Util::OptionSet& options) override {}
  void handleOption(const std::string& name,
                    const std::string& value) override {}

  int main(const std::vector<std::string>& args) override;

  void initialize(Application& self) override {
    Poco::Util::Application::initialize(self);
  }
  void uninitialize() override { Poco::Util::Application::uninitialize(); }

 private:
  Poco::Net::SocketAddress socketBindListen(Poco::Net::ServerSocket& socket,
                                            const std::string& host,
                                            unsigned int port,
                                            bool secure = false) const;
};


class MySQLTCPHandlerFactory : public Poco::Net::TCPServerConnectionFactory {
 private:
  class DummyTCPHandler : public Poco::Net::TCPServerConnection {
   public:
    using Poco::Net::TCPServerConnection::TCPServerConnection;
    void run() override {
      try {
        Poco::Timestamp now;
        std::string dt(Poco::DateTimeFormatter::format(now, _format));
        dt.append("\r\n");
        socket().sendBytes(dt.data(), (int)dt.length());
      } catch (Poco::Exception& e) {
      }
    }

   private:
    std::string _format = "%dd %H:%M:%S.%i";
    };

 public:
  MySQLTCPHandlerFactory() {}

  Poco::Net::TCPServerConnection* createConnection(
      const Poco::Net::StreamSocket& socket) override {
    try {
      LOG_TRACE("Keeper request. Address: %s",
                socket.peerAddress().toString().c_str());
      return new MySQLTCPHandler(socket);
    } catch (const Poco::Net::NetException&) {
      LOG_TRACE(
          "TCP Request. Client is not connected (most likely RST packet was "
          "sent).");
      return new DummyTCPHandler(socket);
    }
  }
};

}  // namespace keeper_server
